package org.example.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Slf4j
@Component
//@Aspect
/**
 * Spring AOP 通知类型
 *
 * @Around
 * 环绕通知，此注解标注的通知方法在目标方法前、后都被执行
 * @Before
 * 前置通知，此注解标注的通知方法在目标方法前被执行
 * @After
 * 后置通知，此注解标注的通知方法在目标方法后被执行，无论是否有异常都会执行
 * @AfterReturning
 * 返回后通知，此注解标注的通知方法在目标方法后被执行，有异常不会执行
 * @AfterThrowing
 * 异常后通知，此注解标注的通知方法发生异常后执行
 *
 * 需要注意的是：当切入点方法使用private修饰时，仅能在当前切面类中引用该表达式， 当外部其他切面类中也要引用当前类中的切入点表达式，
 * 就需要把private改为public
 */
public class MyAspect1 {
    //切入点方法（公共的切入点表达式）
    @Pointcut("execution(* org.example.service.*.*(..))")
    private void pt(){}
    //前置通知
    @Before("pt()")
    public void before(JoinPoint joinPoint){
        log.info("before ...");

    }

    //环绕通知
    @Around("pt()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        log.info("around before ...");

        //调用目标对象的原始方法执行
        Object result = proceedingJoinPoint.proceed();
        
        //原始方法如果执行时有异常，环绕通知中的后置代码不会在执行了
        
        log.info("around after ...");
        return result;
    }

    //后置通知
    @After("pt()")
    public void after(JoinPoint joinPoint){
        log.info("after ...");
    }

    //返回后通知（程序在正常执行的情况下，会执行的后置通知）
    @AfterReturning("pt()")
    public void afterReturning(JoinPoint joinPoint){
        log.info("afterReturning ...");
    }

    //异常通知（程序在出现异常的情况下，执行的后置通知）
    @AfterThrowing("pt()")
    public void afterThrowing(JoinPoint joinPoint){
        log.info("afterThrowing ...");
    }
}
